package com.treeroot.treenet.protocol.http;

import com.treeroot.treenet.entity.Request;
import com.treeroot.treenet.entity.Response;
import com.treeroot.treenet.enums.ProtocolTypeMenu;
import com.treeroot.treenet.protocol.BaseProtocolHandle;
import com.treeroot.treenet.protocol.ConnectDataCallback;
import com.treeroot.treenet.protocol.abs.tcp.AbsTcpConnection;
import com.treeroot.treenet.protocol.abs.tcp.session.TcpSession;
import com.treeroot.treenet.protocol.help.ByteBufferInputStream;
import com.treeroot.treenet.protocol.help.ExecutePreviousHelp;
import com.treeroot.treenet.strategy.ProtocolStrategyHandle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.function.Consumer;

/**
 * Create By TreeRoot
 * Create Time: 2023/12/18 03:43
 * Class Name: HandleHttpProtocol
 * Description:
 * 处理Http协议
 *
 * @author TreeRoot
 */
public class HandleHttpProtocol extends AbsTcpConnection implements BaseProtocolHandle<TcpSession>,
        ProtocolStrategyHandle {
    private static final Logger log = LoggerFactory.getLogger(HandleHttpProtocol.class);

    @Override
    public void handleRequest(ProtocolTypeMenu protocolType) {
        log.info("开始处理 HandleTcpRequest.handleRequest");
        this.handleRequest(this::acceptConnection);
        log.info("结束处理 HandleTcpRequest.handleRequest");
    }


    /**
     * 监听处理连接
     */
    @Override
    public void acceptConnection(TcpSession baseTcpVo) {
        ServerSocketChannel serverSocketChannel = baseTcpVo.getServerSocketChannel();
        //1.接受客户端连接请求
        try (SocketChannel socketChannel = serverSocketChannel.accept()) {
            if (socketChannel != null) {
                log.info("接受到客户端连接: {}", socketChannel.getRemoteAddress());
                //2.设置为非阻塞模式
                socketChannel.configureBlocking(false);
                //3.注册选择器，指定监听事件为 OP_READ(读取数据 读就绪)
                socketChannel.register(baseTcpVo.getSelector(), SelectionKey.OP_READ);
                readDataFromClient(socketChannel.keyFor(baseTcpVo.getSelector()),()-> System.out.println("客户端关闭连接"));
            }
        } catch (Exception e) {
            log.warn("HandleTcpRequest.handleRequest: 无法创建 ServerSocket", e);
        }
    }

    /**
     * 从客户端读取数据
     *
     * @param key 键
     */
    @Override
    public void readDataFromClient(SelectionKey key, ConnectDataCallback connectDataCallback) {
        try (SocketChannel socketChannel = (SocketChannel) key.channel()) {
            ByteBuffer buffer = ByteBuffer.allocate(1024 * 64);
            int bytesRead = socketChannel.read(buffer);
            if (bytesRead == -1) {
                log.error("客户端关闭连接: {}", socketChannel.getRemoteAddress());
                socketChannel.close();
                key.cancel();
                return;
            }
            buffer.flip();
            byte[] bytes = new byte[buffer.remaining()];
            buffer.get(bytes);
            String data = new String(bytes);
            if (!ExecutePreviousHelp.checkIsStandardHttp(data)) {
                log.error("not a valid http protocol");
                buffer.clear();
                return;
            }
            // todo:把读完的消息给真正的服务器,并且等待服务器返回数据再返回给客户端
            log.info("客户端地址：{}", socketChannel.getRemoteAddress());
            log.info("客户端消息：\n{}", data);
            buffer.clear();
            // todo: 再开放一条通道给真正的服务器,并等待服务器返回数据再返回本通道,再由本通道返回给客户端
            // 指定字符编码
            Charset charset = StandardCharsets.UTF_8;
            CharBuffer charBuffer = charset.decode(buffer);
            BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteBufferInputStream(charBuffer)));
            Request request = Request.parse2request(reader);
            String responseMsg = "{\n" +
                    "  \"code\": 200,\n" +
                    "  \"msg\": \"请求成功\",\n" +
                    "  \"data\": {\n" +
                    "    \"id\": 1,\n" +
                    "    \"name\": \"John Doe\",\n" +
                    "    \"email\": \"johndoe@example.com\"\n" +
                    "  }\n" +
                    "}";
            // 构建响应消息
            String response = Response.buildResponse(request, responseMsg);
            socketChannel.write(StandardCharsets.UTF_8.encode(response));
            buffer.clear();
        } catch (IOException e) {
            log.error("读取客户端数据时发生错误", e);
            key.cancel();
        }
    }


    @Override
    public void handleRequest(Consumer<TcpSession> acceptConnectionConsumer) {
        super.handleRequest(acceptConnectionConsumer);

    }

    @Override
    public void acceptBefore(TcpSession baseTcpVo) {

    }

    @Override
    public void acceptAfter(TcpSession baseTcpVo) {

    }
}
